home *** CD-ROM | disk | FTP | other *** search
- Subject: v16i083: Mail delivery program, Part03/03
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Chip Salzenberg <chip@ateng.uu.net>
- Posting-number: Volume 16, Issue 83
- Archive-name: deliver/part03
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: main.c mbox.c procs.c subs.c sysdep.c uucp.c
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'main.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'main.c'\"
- else
- echo shar: Extracting \"'main.c'\" \(9621 characters\)
- sed "s/^X//" >'main.c' <<'END_OF_FILE'
- X/* $Header: main.c,v 1.5 88/09/14 20:00:03 network Exp $
- X *
- X * A program to deliver local mail with some flexibility.
- X *
- X * $Log: main.c,v $
- X * Revision 1.5 88/09/14 20:00:03 network
- X * Add version string, including patchlevel.
- X *
- X * Revision 1.4 88/09/14 19:41:54 network
- X * Portability to System V and BSD.
- X * General fixup.
- X *
- X * Revision 1.3 88/08/30 16:13:54 network
- X * Remove general subroutines to new module, subs.c.
- X *
- X * Revision 1.2 88/08/25 15:29:59 network
- X * Implement -s and -u options and ENV_SYSDEL and ENV_USERDEL environment
- X * variables. Tighten up control over effective and real uid/gid.
- X * In particular, renounce setuid privileges if the system or user delivery
- X * file is specified.
- X *
- X * Revision 1.1 88/06/06 09:38:54 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X#include "patchlevel.h"
- X#include <signal.h>
- X
- X/*
- X * External data.
- X */
- X
- X/* Variables set by getopt() [blech] */
- X
- Xextern int optind, opterr;
- Xextern char *optarg;
- X
- X/*
- X * Global data
- X */
- X
- Xint verbose = FALSE;
- Xint dryrun = FALSE;
- Xint printaddrs = FALSE;
- Xint leavetemps = FALSE;
- Xint boxdelivery = FALSE;
- X
- Xchar *progname = "deliver";
- Xchar version[32] = "1.0";
- Xchar *shell = SHELL;
- X
- Xchar *sys_deliver = NULL;
- Xchar *user_deliver = NULL;
- Xchar *sender = NULL;
- Xchar *hostname = NULL;
- X
- Xint eff_uid = -1;
- Xint eff_gid = -1;
- Xint real_uid = -1;
- Xint real_gid = -1;
- X
- XCONTEXT *eff_ct = NULL;
- XCONTEXT *real_ct = NULL;
- X
- Xchar *ttype[T_MAX] = { "header", "body" };
- Xchar *tfile[T_MAX] = { NULL, NULL };
- Xint tfd[T_MAX] = { -1, -1 };
- X
- X/*----------------------------------------------------------------------
- X * The Program.
- X */
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X char *p;
- X int u, c, errcount, insecure;
- X
- X /* Make sure that stdout and stderr are interleaved correctly */
- X
- X (void) Linebuf(stdout);
- X (void) Linebuf(stderr);
- X
- X /* Figure out the name used to invoke this program. */
- X
- X progname = basename(argv[0]);
- X
- X /* What version of the program is this? */
- X
- X sprintf(version + strlen(version), ".%02d", PATCHLEVEL);
- X
- X /* Figure out the name of this host */
- X
- X if ((hostname = gethost()) == NULL)
- X {
- X hostname = "unknown";
- X error("unable to determine host name; using \"%s\"\n",
- X hostname);
- X }
- X
- X /* Process environment: handle recursive invocation */
- X
- X if ((p = getenv(ENV_DFLAGS)) != NULL)
- X {
- X while (*p)
- X {
- X switch (*p++)
- X {
- X case 'v':
- X verbose = TRUE;
- X break;
- X case 'd':
- X verbose = TRUE;
- X dryrun = TRUE;
- X break;
- X case 'A':
- X printaddrs = TRUE;
- X dryrun = TRUE;
- X break;
- X case 't':
- X leavetemps = TRUE;
- X break;
- X }
- X }
- X }
- X if ((p = getenv(ENV_SYSDEL)) != NULL)
- X sys_deliver = p;
- X if ((p = getenv(ENV_USERDEL)) != NULL)
- X user_deliver = p;
- X if ((p = getenv(ENV_SENDER)) != NULL)
- X sender = p;
- X if ((p = getenv(ENV_HOSTNAME)) != NULL)
- X hostname = p;
- X
- X /* Parse command line arguments */
- X
- X while ((c = getopt(argc, argv, "vdAtbs:u:r:h:")) != EOF)
- X {
- X switch (c)
- X {
- X case 'v':
- X verbose = TRUE;
- X break;
- X case 'd':
- X verbose = TRUE;
- X dryrun = TRUE;
- X break;
- X case 'A':
- X printaddrs = TRUE;
- X dryrun = TRUE;
- X break;
- X case 't':
- X leavetemps = TRUE;
- X break;
- X case 'b':
- X boxdelivery = TRUE;
- X break;
- X case 's':
- X sys_deliver = optarg;
- X break;
- X case 'u':
- X user_deliver = optarg;
- X break;
- X case 'r':
- X sender = optarg;
- X break;
- X case 'h':
- X hostname = optarg;
- X break;
- X case '?':
- X usage();
- X }
- X }
- X
- X /* If no destinations were given, forget it. */
- X
- X if (optind >= argc)
- X {
- X message("%s: no recipients specified\n", progname);
- X usage();
- X }
- X
- X /* Print a debugging message */
- X
- X if (verbose)
- X {
- X message("%s %s running on host %s\n",
- X progname, version, hostname);
- X if (sender && *sender)
- X message("Sender is %s\n", sender);
- X }
- X
- X /* Find effective and real uids and gids. */
- X
- X eff_uid = geteuid();
- X eff_gid = getegid();
- X real_uid = getuid();
- X real_gid = getgid();
- X
- X if (eff_uid != real_uid && eff_uid != 0)
- X {
- X message("%s: if setuid, must be setuid root\n");
- X leave(1);
- X }
- X
- X /* Renounce special privileges if something insecure was requested. */
- X
- X if (sys_deliver || user_deliver)
- X {
- X if (setgid(eff_gid = real_gid) == -1
- X || setuid(eff_uid = real_uid) == -1)
- X {
- X syserr("%s: can't renounce setuid privileges");
- X leave(1);
- X }
- X }
- X
- X /* Get the contexts of our effective and real uids. */
- X
- X if ((eff_ct = uid_context(eff_uid)) == NULL)
- X error("invalid effective uid %d!?\n", eff_uid);
- X
- X if ((real_ct = uid_context(real_uid)) == NULL)
- X error("invalid real uid %d!?\n", real_uid);
- X
- X if (!eff_ct || !real_ct)
- X leave(1);
- X
- X if (verbose)
- X {
- X message("effective uid = %s (%d/%d); real uid = %s (%d/%d)\n",
- X eff_ct->name, eff_ct->uid, eff_ct->gid,
- X real_ct->name, real_ct->uid, real_ct->gid);
- X }
- X
- X /* Let's be sane about the file creation mask. */
- X
- X u = umask(0);
- X u &= ~0700; /* Let's not deprive ourselves of permissions. */
- X u |= 022; /* Let's be reasonably paranoid about writing. */
- X (void) umask(u);
- X
- X /* Turn off all intrusive signals (unless we're not delivering). */
- X
- X if (! dryrun)
- X {
- X (void) signal(SIGHUP, SIG_IGN);
- X (void) signal(SIGINT, SIG_IGN);
- X (void) signal(SIGQUIT, SIG_IGN);
- X }
- X
- X /*
- X * Create the temporary files and write the message to them.
- X */
- X
- X if (copy_message() < 0)
- X leave(1);
- X
- X /*
- X * Set up useful environment variables.
- X * Note that this must be done _after_ copy_message(),
- X * since that's where the temp files are created.
- X */
- X
- X setup_environ();
- X
- X /*
- X * Assign the default delivery file names.
- X * Note that this must be after setup_environ(), or else the
- X * environment won't reflect specified/unspecified options.
- X */
- X
- X if (!sys_deliver)
- X sys_deliver = SYS_DELIVER;
- X if (!user_deliver)
- X user_deliver = USER_DELIVER;
- X
- X /*
- X * Perhaps we should consider all arguments as mailbox names...
- X */
- X
- X if (boxdelivery)
- X {
- X int a;
- X
- X if (verbose)
- X message("mailbox delivery as %s\n", real_ct->name);
- X
- X /*
- X * Consider all arguments as mailbox filenames.
- X */
- X
- X for (a = optind; a < argc; ++a)
- X (void) dest(real_ct->name, argv[a]);
- X
- X if (verbose)
- X dumpdests("(should all be mailboxes)");
- X }
- X
- X /*
- X * They're not mailbox names, so they should be mail addresses.
- X */
- X
- X else
- X {
- X /*
- X * Run all destinations though the system delivery file.
- X * If sys_dfile() doesn't find one, it will call dest()
- X * on each address.
- X */
- X
- X sys_dfile(argc - optind, argv + optind);
- X
- X if (verbose)
- X dumpdests("after running system delivery file");
- X
- X /*
- X * Run each user destination through his delivery file.
- X */
- X
- X user_dfiles();
- X
- X if (verbose)
- X dumpdests("after running user delivery files");
- X }
- X
- X /*
- X * Drop mail in mailbox(es).
- X */
- X
- X mbox_deliver();
- X
- X if (verbose)
- X dumpdests("after delivery to all mailboxes");
- X
- X /*
- X * Send mail to UUCP address(es).
- X */
- X
- X uucp_deliver();
- X
- X if (verbose)
- X dumpdests("after delivery to UUCP addresses");
- X
- X /*
- X * Report any errors, and leave.
- X */
- X
- X errcount = report_errors();
- X
- X /*
- X * All done.
- X */
- X
- X leave(errcount ? 1 : 0);
- X /* NOTREACHED */
- X}
- X
- X/*----------------------------------------------------------------------
- X * Print a usage message and exit.
- X */
- X
- Xusage()
- X{
- X message("Usage: %s [-b][-A][-d][-v][-t][-r from][-h host] args\n", progname);
- X message("-b All arguments are mailbox filenames.\n");
- X message(" (Default: arguments are user names.)\n");
- X message("-A Resolve addresses but do not deliver.\n");
- X message("-d Be verbose but do not deliver.\n");
- X message("-v Be verbose and deliver.\n");
- X message("-t Do not remote temp files before exiting.\n");
- X message("-r from Specify the address to appear in the \"From \" line.\n");
- X message("-h host Specify the host name.\n");
- X message(" (This option overrides any \"From \" line in the input.)\n");
- X message("args Either user addresses or mailboxes (-b).\n");
- X leave(1);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Clean up and exit.
- X */
- X
- Xleave(code)
- Xint code;
- X{
- X if (! leavetemps)
- X {
- X int t;
- X
- X for (t = 0; t < T_MAX; ++t)
- X {
- X if (tfile[t] && unlink(tfile[t]) == -1)
- X syserr("can't unlink %s", tfile[t]);
- X }
- X }
- X
- X exit(code);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Report any errors to stderr.
- X * Return an error count.
- X */
- X
- Xint
- Xreport_errors()
- X{
- X DEST *d;
- X int count = 0;
- X
- X for (d = first_dest(); d; d = next_dest(d))
- X {
- X if (d->state != ST_ERROR)
- X continue;
- X
- X if (++count == 1)
- X {
- X error(
- X "delivery to the following address(es) failed on host %s\n",
- X hostname);
- X }
- X
- X message("\tuser \"%s\"", d->name);
- X if (d->class == CL_MBOX)
- X message(", mailbox \"%s\"", d->mailbox);
- X message(": %s\n", d->error);
- X }
- X
- X return count;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Set up useful environment variables.
- X */
- X
- Xsetup_environ()
- X{
- X char flags[8];
- X int f = 0;
- X
- X flags[f++] = '-';
- X if (verbose)
- X flags[f++] = (dryrun ? 'd' : 'v');
- X if (printaddrs)
- X flags[f++] = 'A';
- X if (leavetemps)
- X flags[f++] = 't';
- X flags[f] = 0;
- X
- X alloc_env(ENV_DFLAGS, (f > 1) ? flags : "");
- X if (sys_deliver && *sys_deliver)
- X alloc_env(ENV_SYSDEL, sys_deliver);
- X if (user_deliver && *user_deliver)
- X alloc_env(ENV_USERDEL, user_deliver);
- X if (hostname && *hostname)
- X alloc_env(ENV_HOSTNAME, hostname);
- X if (sender && *sender)
- X alloc_env(ENV_SENDER, sender);
- X
- X alloc_env(ENV_HEADER, tfile[T_HEADER]);
- X alloc_env(ENV_BODY, tfile[T_BODY]);
- X
- X alloc_env("IFS", " \t\n");
- X}
- END_OF_FILE
- if test 9621 -ne `wc -c <'main.c'`; then
- echo shar: \"'main.c'\" unpacked with wrong size!
- fi
- # end of 'main.c'
- fi
- if test -f 'mbox.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mbox.c'\"
- else
- echo shar: Extracting \"'mbox.c'\" \(4767 characters\)
- sed "s/^X//" >'mbox.c' <<'END_OF_FILE'
- X/* $Header: mbox.c,v 1.2 88/09/14 19:42:06 network Exp $
- X *
- X * Finally! Put the message in the specified mailbox(es).
- X *
- X * $Log: mbox.c,v $
- X * Revision 1.2 88/09/14 19:42:06 network
- X * Portability to System V and BSD.
- X * General fixup.
- X *
- X * Revision 1.1 88/06/06 09:39:06 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <errno.h>
- X
- X/*
- X * External data.
- X */
- X
- Xextern int errno;
- X
- X/*
- X * Local functions.
- X */
- X
- Xstatic mbox_dest();
- Xstatic int mbox_write();
- Xstatic int mbox_copy();
- X
- X/*----------------------------------------------------------------------
- X * Deliver mail to all valid destinations.
- X */
- X
- Xmbox_deliver()
- X{
- X DEST *d;
- X
- X for (d = first_dest(); d; d = next_dest(d))
- X {
- X switch (d->class)
- X {
- X case CL_USER:
- X case CL_MBOX:
- X if (d->state == ST_WORKING)
- X mbox_dest(d);
- X break;
- X }
- X }
- X}
- X
- X/*----------------------------------------------------------------------
- X * Deliver mail to one destination.
- X */
- X
- Xstatic
- Xmbox_dest(d)
- XDEST *d;
- X{
- X CONTEXT *ct;
- X int ret = 0;
- X
- X if (printaddrs)
- X {
- X (void) printf("%s", d->name);
- X if (d->class == CL_MBOX)
- X (void) printf(":%s", d->mailbox);
- X (void) printf("\n");
- X }
- X
- X if (dryrun)
- X {
- X d->state = ST_DONE;
- X return;
- X }
- X
- X if ((ct = name_context(d->name)) == NULL)
- X {
- X d->state = ST_ERROR;
- X d->error = "Lost context in mbox_dest()";
- X return;
- X }
- X
- X if (! ok_context(ct))
- X {
- X d->state = ST_ERROR;
- X d->error = "No permissions for that context";
- X return;
- X }
- X
- X if (d->class == CL_MBOX)
- X {
- X give_temps(ct);
- X
- X if (sfork() == 0)
- X {
- X if (become(ct, !boxdelivery) < 0)
- X exit(1);
- X if (mbox_write(d->mailbox, ct, FALSE) < 0)
- X exit(1);
- X exit(0);
- X }
- X
- X if (await_child() != 0)
- X ret = -1;
- X }
- X else
- X {
- X char mailbox[100];
- X
- X (void) sprintf(mailbox, "%s/%s",
- X#ifdef MAILBOX_DIR
- X MAILBOX_DIR, d->name
- X#else
- X d->home, MAILBOX_NAME
- X#endif
- X );
- X
- X if (mbox_write(mailbox, ct, TRUE) < 0)
- X ret = -1;
- X }
- X
- X if (ret >= 0)
- X d->state = ST_DONE;
- X else
- X {
- X d->state = ST_ERROR;
- X d->error = "Error writing to mailbox";
- X }
- X}
- X
- X/*----------------------------------------------------------------------
- X * Write mail to the named mailbox.
- X * If we have to create the mailbox, give it to the specified user.
- X * If "is_sys" is true, then we're writing to a system mailbox.
- X */
- X
- Xstatic int
- Xmbox_write(mailbox, ct, is_sys)
- Xchar *mailbox;
- XCONTEXT *ct;
- Xint is_sys;
- X{
- X int fd, t;
- X int ret = 0;
- X
- X if (verbose)
- X {
- X message("As %s, delivering to %s mailbox %s\n",
- X ct->name, (is_sys ? "system" : "user"), mailbox);
- X }
- X
- X if (lock_name(mailbox) < 0)
- X return -1;
- X
- X while ((fd = open(mailbox, O_RDWR)) == -1)
- X {
- X if (errno != ENOENT)
- X {
- X syserr("can't open %s", mailbox);
- X break;
- X }
- X
- X if ((fd = open(mailbox, O_RDWR|O_CREAT|O_EXCL,
- X MAILBOX_MODE)) != -1)
- X {
- X /* Make sure the mailbox receives the correct modes */
- X
- X int mbox_gid = ct->gid;
- X
- X#ifdef MAILBOX_GROUP
- X if (is_sys)
- X {
- X static int mbox_gid_sv = -2;
- X
- X if (mbox_gid_sv == -2)
- X mbox_gid_sv = group_id(MAILBOX_GROUP);
- X
- X if (mbox_gid_sv < 0)
- X message("%s: no such group\n", MAILBOX_GROUP);
- X else
- X mbox_gid = mbox_gid_sv;
- X }
- X#endif /* MAILBOX_GROUP */
- X
- X if (chown(mailbox, ct->uid, mbox_gid) == -1)
- X {
- X /* print a message, but that's all. (???) */
- X syserr("can't chown %s to %d,%d",
- X mailbox, ct->uid, mbox_gid);
- X }
- X break;
- X }
- X
- X if (errno != EEXIST)
- X {
- X syserr("can't create %s", mailbox);
- X break;
- X }
- X }
- X
- X if (fd == -1)
- X {
- X (void) unlock_name(mailbox);
- X return -1;
- X }
- X
- X if (lock_fd(fd) < 0)
- X {
- X (void) close(fd);
- X (void) unlock_name(mailbox);
- X return -1;
- X }
- X
- X (void) lseek(fd, 0L, 2); /* No error check: may be a special file */
- X
- X for (t = 0; t < T_MAX; ++t)
- X {
- X if (lseek(tfd[t], 0L, 0) == -1)
- X {
- X syserr("lseek in %s file %s", ttype[t], tfile[t]);
- X ret = -1;
- X break;
- X }
- X
- X switch (mbox_copy(tfd[t], fd))
- X {
- X case 1:
- X syserr("can't read %s file %s", ttype[t], tfile[t]);
- X ret = -1;
- X break;
- X case 2:
- X syserr("can't write to mailbox %s as %s",
- X mailbox, ct->name);
- X ret = -1;
- X break;
- X default:
- X continue;
- X }
- X break;
- X }
- X
- X if (verbose)
- X {
- X if (ret >= 0)
- X message("wrote message to %s\n", mailbox);
- X }
- X
- X if (unlock_fd(fd) < 0)
- X ret = -1;
- X (void) close(fd);
- X if (unlock_name(mailbox) < 0)
- X ret = -1;
- X
- X return ret;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Copy the named file to the given file descriptor.
- X */
- X
- Xstatic int
- Xmbox_copy(ifd, ofd)
- Xint ifd;
- Xint ofd;
- X{
- X char buf[BUFSIZ];
- X int rd;
- X
- X while ((rd = read(ifd, buf, sizeof(buf))) > 0)
- X {
- X errno = 255; /* to avoid bogus syserr() output */
- X if (write(ofd, buf, (unsigned) rd) != rd)
- X return 2;
- X }
- X
- X if (rd == -1)
- X return 1;
- X
- X return 0;
- X}
- END_OF_FILE
- if test 4767 -ne `wc -c <'mbox.c'`; then
- echo shar: \"'mbox.c'\" unpacked with wrong size!
- fi
- # end of 'mbox.c'
- fi
- if test -f 'procs.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procs.c'\"
- else
- echo shar: Extracting \"'procs.c'\" \(5021 characters\)
- sed "s/^X//" >'procs.c' <<'END_OF_FILE'
- X/* $Header: procs.c,v 1.2 88/09/14 19:42:28 network Exp $
- X *
- X * Process management and misc support.
- X *
- X * $Log: procs.c,v $
- X * Revision 1.2 88/09/14 19:42:28 network
- X * Portability to System V and BSD.
- X * General fixup.
- X *
- X * Revision 1.1 88/06/06 09:39:15 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X#include <errno.h>
- X#include <signal.h>
- X
- X/*
- X * External data.
- X */
- X
- Xextern int errno;
- X
- X/*
- X * Local data.
- X */
- X
- Xstatic int child_pid = -1;
- Xstatic int (*saved_sigpipe)() = SIG_DFL;
- X
- X/*----------------------------------------------------------------------
- X * Like popen(), but execute the child in a specific context.
- X * Also, the argument list is already a vector.
- X */
- X
- XFILE *
- Xct_popenv(ct, prog, av, mode)
- XCONTEXT *ct;
- Xchar *prog;
- Xchar **av;
- Xchar *mode;
- X{
- X char ch;
- X int child, parent;
- X int pfd[2];
- X
- X if (!ct || !prog || !av || !mode)
- X return NULL;
- X
- X if (mode[0] == 'r' && mode[1] == 0)
- X child = 1, parent = 0;
- X else if (mode[0] == 'w' && mode[1] == 0)
- X child = 0, parent = 1;
- X else
- X return NULL;
- X
- X /* We can't have more than one child at a time. */
- X
- X if (child_pid >= 0)
- X {
- X error("in ct_popen: a process is already open\n");
- X return NULL;
- X }
- X
- X /* Make a stab at predicting uid-related failure. */
- X
- X if (! ok_context(ct))
- X {
- X error("in ct_popen: no permissions to become %s\n", ct->name);
- X return NULL;
- X }
- X
- X /* Pipes? Like, tubular, fer shur! */
- X
- X if (pipe(pfd) == -1)
- X {
- X syserr("can't create a pipe");
- X return NULL;
- X }
- X
- X /* Generate a debugging message. */
- X
- X if (verbose)
- X {
- X int a;
- X
- X message("Spawning");
- X for (a = 0; av[a]; ++a)
- X message(" %s", av[a]);
- X message("\n");
- X }
- X
- X /* Handle the child case */
- X
- X if (sfork() == 0)
- X {
- X if (child == 0)
- X {
- X (void) close(0);
- X (void) dup(pfd[0]); /* ass_u_me 0 */
- X }
- X else
- X {
- X (void) close(0);
- X if (open("/dev/null", O_RDONLY) != 0)
- X {
- X /* This should _never_ happen, but... */
- X syserr("can't open /dev/null");
- X (void) dup(1); /* ass_u_me 0 */
- X }
- X
- X (void) close(1);
- X (void) dup(pfd[1]); /* ass_u_me 1 */
- X }
- X
- X if (become(ct, TRUE) < 0)
- X (void) write(pfd[1], "n", 1);
- X else
- X {
- X int t;
- X
- X (void) write(pfd[1], "y", 1);
- X
- X (void) close(pfd[child]);
- X (void) close(pfd[parent]);
- X for (t = 0; t < T_MAX; ++t)
- X (void) close(tfd[t]);
- X
- X (void) execv(prog, av);
- X syserr("can't execute %s", prog);
- X }
- X
- X exit(127);
- X }
- X
- X /* Make sure that a broken pipe won't kill us */
- X
- X saved_sigpipe = signal(SIGPIPE, SIG_IGN);
- X
- X /* The child must report "OK" before we continue. */
- X
- X if ((read(pfd[0], &ch, 1) < 1) || (ch != 'y'))
- X {
- X (void) close(pfd[0]);
- X (void) close(pfd[1]);
- X (void) await_child();
- X return NULL;
- X }
- X
- X (void) close(pfd[child]);
- X return fdopen(pfd[parent], mode);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Close the stream opened by ct_popen().
- X */
- X
- Xct_pclose(fp)
- XFILE *fp;
- X{
- X if (fp)
- X (void) fclose(fp);
- X return await_child();
- X}
- X
- X/*----------------------------------------------------------------------
- X * Assume the identity of the given user.
- X */
- X
- Xint
- Xbecome(ct, chd)
- XCONTEXT *ct;
- Xint chd;
- X{
- X char env_path[32];
- X
- X /*
- X * Assume a new identity.
- X * Note the importance of doing the setgid() before the setuid().
- X */
- X
- X if (setgid(ct->gid) == -1)
- X {
- X syserr("can't setgid to %d", ct->gid);
- X return -1;
- X }
- X if (setuid(ct->uid) == -1)
- X {
- X syserr("can't setgid to %u", ct->uid);
- X return -1;
- X }
- X if (chd && chdir(ct->home) == -1)
- X {
- X syserr("can't chdir to %s", ct->home);
- X return -1;
- X }
- X
- X /* Set up the environment */
- X
- X (void) sprintf(env_path, "%s:/bin:/usr/bin",
- X ((ct->uid == 0) ? "/etc" : "."));
- X alloc_env("HOME", ct->home);
- X alloc_env("PATH", env_path);
- X
- X /* I guess it worked. */
- X
- X return 0;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Safe fork. If it doesn't work, it exits.
- X */
- X
- Xint
- Xsfork()
- X{
- X int tries;
- X
- X /*
- X * A few safety measures.
- X */
- X
- X (void) await_child();
- X (void) fflush(stdout);
- X (void) fflush(stderr);
- X
- X /*
- X * Be patient in waiting for a fork().
- X */
- X
- X for (tries = 0; tries < 10; ++tries)
- X {
- X if (tries)
- X snooze(3);
- X if ((child_pid = fork()) >= 0)
- X return child_pid;
- X if (errno != EAGAIN)
- X break;
- X }
- X
- X syserr("can't fork");
- X leave(1);
- X /* NOTREACHED */
- X}
- X
- X/*----------------------------------------------------------------------
- X * Wait for our child (if any) to exit.
- X * Returns child's exit status or -1 if there is a problem.
- X */
- X
- Xint
- Xawait_child()
- X{
- X int wpid, st;
- X
- X if (child_pid < 0)
- X return -1;
- X
- X while ((wpid = wait(&st)) >= 0)
- X {
- X if (wpid == child_pid)
- X break;
- X }
- X
- X child_pid = -1;
- X if (wpid == -1)
- X syserr("waiting for child");
- X
- X (void) signal(SIGPIPE, saved_sigpipe);
- X saved_sigpipe = SIG_DFL;
- X
- X if (wpid == -1)
- X return -1;
- X
- X if (st & 0xFF)
- X {
- X error("child process died%s due to signal %d.\n",
- X ((st & 0x80) ? " and dumped core" : ""),
- X (st & 0x7F));
- X
- X return -1;
- X }
- X
- X if (verbose)
- X {
- X message("child process exited with status %d.\n",
- X (st >> 8) & 0xFF);
- X }
- X
- X return ((st >> 8) & 0xFF);
- X}
- END_OF_FILE
- if test 5021 -ne `wc -c <'procs.c'`; then
- echo shar: \"'procs.c'\" unpacked with wrong size!
- fi
- # end of 'procs.c'
- fi
- if test -f 'subs.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'subs.c'\"
- else
- echo shar: Extracting \"'subs.c'\" \(2050 characters\)
- sed "s/^X//" >'subs.c' <<'END_OF_FILE'
- X/* $Header: subs.c,v 1.3 88/09/14 19:42:33 network Exp $
- X *
- X * Miscellaneous subroutines.
- X *
- X * $Log: subs.c,v $
- X * Revision 1.3 88/09/14 19:42:33 network
- X * Portability to System V and BSD.
- X * General fixup.
- X *
- X * Revision 1.2 88/08/30 16:14:53 network
- X * New module. Includes routines from main.c.
- X * Also, new routine savestr().
- X *
- X */
- X
- X#include "deliver.h"
- X
- X/*----------------------------------------------------------------------
- X * Allocate memory for an environment variable, and putenv() it.
- X */
- X
- Xalloc_env(name, value)
- Xchar *name;
- Xchar *value;
- X{
- X char *s;
- X
- X if (!name || !value)
- X return;
- X
- X s = zalloc((unsigned) (strlen(name) + strlen(value) + 2));
- X (void) sprintf(s, "%s=%s", name, value);
- X if (putenv(s))
- X nomem();
- X}
- X
- X/*----------------------------------------------------------------------
- X * Allocate and clear. If it fails, it takes the emergency exit.
- X */
- X
- Xchar *
- Xzalloc(size)
- Xunsigned size;
- X{
- X char *p;
- X
- X if ((p = malloc(size)) == NULL)
- X nomem();
- X
- X (void) Zero(p, size);
- X return p;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Reallocate to new size. If it fails, it takes the emergency exit.
- X */
- X
- Xchar *
- Xsrealloc(ptr, size)
- Xchar *ptr;
- Xunsigned size;
- X{
- X char *p;
- X
- X if ((p = realloc(ptr, size)) == NULL)
- X nomem();
- X
- X return p;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Make an allocated copy of a string.
- X */
- X
- Xchar *
- Xcopystr(s)
- Xchar *s;
- X{
- X char *p;
- X
- X if (s == NULL)
- X return NULL;
- X
- X if ((p = malloc((unsigned) strlen(s) + 1)) == NULL)
- X nomem();
- X
- X (void) strcpy(p, s);
- X return p;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Emergency exit for memory loss.
- X */
- X
- Xnomem()
- X{
- X message("%s: out of memory\n", progname);
- X leave(1);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Return the last component of the given pathname.
- X */
- X
- Xchar *
- Xbasename(name)
- Xchar *name;
- X{
- X char *b;
- X
- X if ((b = strrchr(name, '/')) != NULL)
- X ++b;
- X else
- X b = name;
- X
- X return (b);
- X}
- END_OF_FILE
- if test 2050 -ne `wc -c <'subs.c'`; then
- echo shar: \"'subs.c'\" unpacked with wrong size!
- fi
- # end of 'subs.c'
- fi
- if test -f 'sysdep.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sysdep.c'\"
- else
- echo shar: Extracting \"'sysdep.c'\" \(5242 characters\)
- sed "s/^X//" >'sysdep.c' <<'END_OF_FILE'
- X/* $Header: sysdep.c,v 1.3 88/09/14 20:00:24 network Exp $
- X *
- X * Routines which are (or might well be) system-dependant.
- X * I've put the message routines here since you may need to use
- X * the ANSI <stdarg.h> instead of <varargs.h>.
- X *
- X * $Log: sysdep.c,v $
- X * Revision 1.3 88/09/14 20:00:24 network
- X * Fix type of gethostname() for BSD.
- X *
- X * Revision 1.2 88/09/14 19:42:37 network
- X * Portability to System V and BSD.
- X * General fixup.
- X *
- X * Revision 1.1 88/06/06 09:39:29 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X#include <errno.h>
- X#include <varargs.h>
- X
- X#ifdef UNAME
- X#include <sys/utsname.h>
- X#endif
- X
- X/*
- X * External functions.
- X */
- X
- X#ifdef M_XENIX
- Xextern long nap();
- X#else
- Xextern unsigned sleep();
- X#endif
- X
- X/*
- X * External data.
- X */
- X
- Xextern int errno;
- Xextern int sys_nerr;
- Xextern char *sys_errlist[];
- X
- X/*----------------------------------------------------------------------
- X * Print a message.
- X */
- X
- X/* VARARGS1 */
- Xmessage(fmt, va_alist)
- Xchar *fmt;
- Xva_dcl
- X{
- X va_list args;
- X va_start(args);
- X
- X (void) vfprintf(stderr, fmt, args);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Print an error message.
- X */
- X
- X/* VARARGS1 */
- Xerror(fmt, va_alist)
- Xchar *fmt;
- Xva_dcl
- X{
- X va_list args;
- X va_start(args);
- X
- X (void) fprintf(stderr, "%s: ", progname);
- X (void) vfprintf(stderr, fmt, args);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Report an error returned from a system call.
- X */
- X
- X/* VARARGS1 */
- Xsyserr(fmt, va_alist)
- Xchar *fmt;
- Xva_dcl
- X{
- X int e = errno;
- X va_list args;
- X va_start(args);
- X
- X (void) fprintf(stderr, "%s: ", progname);
- X (void) vfprintf(stderr, fmt, args);
- X if (e <= sys_nerr)
- X (void) fprintf(stderr, ": %s\n", sys_errlist[e]);
- X else
- X (void) fprintf(stderr, ": unknown system error %d\n", e);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Sleep for the given number of seconds.
- X */
- X
- Xsnooze(n)
- Xint n;
- X{
- X#ifdef M_XENIX
- X (void) nap(n * 1000L);
- X#else
- X (void) sleep(n);
- X#endif
- X}
- X
- X/*----------------------------------------------------------------------
- X * Get the host name from HOSTFILE.
- X */
- X
- X#ifdef HOSTFILE
- X
- Xchar *
- Xgethost()
- X{
- X int fd, rd;
- X char *p;
- X static char name[32];
- X
- X if ((fd = open(HOSTFILE, O_RDONLY)) == -1)
- X return NULL;
- X rd = read(fd, name, sizeof(name) - 1);
- X (void) close(fd);
- X
- X if (rd < 1)
- X return NULL;
- X name[rd] = 0;
- X if ((p = strchr(name, '\n')) != NULL)
- X *p = 0;
- X
- X return (name[0] ? name : NULL);
- X}
- X
- X#endif /* HOSTFILE */
- X
- X/*----------------------------------------------------------------------
- X * Get the host name via the uname() system call.
- X */
- X
- X#ifdef UNAME
- X
- Xchar *
- Xgethost()
- X{
- X static struct utsname u;
- X
- X uname(&u);
- X return (u.nodename[0] ? u.nodename : NULL);
- X}
- X
- X#endif /* UNAME */
- X
- X/*----------------------------------------------------------------------
- X * Get the host name via the gethostname() system call.
- X */
- X
- X#ifdef GETHOSTNAME
- X
- Xchar *
- Xgethost()
- X{
- X static char hostname[64];
- X
- X if (gethostname(hostname, sizeof(hostname)) == -1)
- X return NULL;
- X
- X return hostname;
- X}
- X
- X#endif /* GETHOSTNAME */
- X
- X/*----------------------------------------------------------------------
- X * Variable-argument-list output, System V style.
- X */
- X
- X#ifndef HAS_VPRINTF
- X
- Xvprintf(fmt, ap)
- Xchar *fmt;
- Xva_list ap;
- X{
- X int a,b,c,d,e,f,g,h;
- X
- X a = va_arg(ap, int);
- X b = va_arg(ap, int);
- X c = va_arg(ap, int);
- X d = va_arg(ap, int);
- X e = va_arg(ap, int);
- X f = va_arg(ap, int);
- X g = va_arg(ap, int);
- X h = va_arg(ap, int);
- X
- X printf(fmt, a,b,c,d,e,f,g,h);
- X}
- X
- Xvfprintf(fp, fmt, ap)
- XFILE *fp;
- Xchar *fmt;
- Xva_list ap;
- X{
- X int a,b,c,d,e,f,g,h;
- X
- X a = va_arg(ap, int);
- X b = va_arg(ap, int);
- X c = va_arg(ap, int);
- X d = va_arg(ap, int);
- X e = va_arg(ap, int);
- X f = va_arg(ap, int);
- X g = va_arg(ap, int);
- X h = va_arg(ap, int);
- X
- X fprintf(fp, fmt, a,b,c,d,e,f,g,h);
- X}
- X
- Xvsprintf(s, fmt, ap)
- Xchar *s;
- Xchar *fmt;
- Xva_list ap;
- X{
- X int a,b,c,d,e,f,g,h;
- X
- X a = va_arg(ap, int);
- X b = va_arg(ap, int);
- X c = va_arg(ap, int);
- X d = va_arg(ap, int);
- X e = va_arg(ap, int);
- X f = va_arg(ap, int);
- X g = va_arg(ap, int);
- X h = va_arg(ap, int);
- X
- X sprintf(s, fmt, a,b,c,d,e,f,g,h);
- X}
- X
- X#endif /* HAS_VPRINTF */
- X
- X/*----------------------------------------------------------------------
- X * Add a new environment variable.
- X */
- X
- X#ifndef HAS_PUTENV
- X
- Xint
- Xputenv(s)
- Xchar *s;
- X{
- X static char **env_array;
- X static int env_size;
- X char *e;
- X int i, j;
- X
- X if (env_array == NULL)
- X {
- X for (i = 0; environ[i]; ++i)
- X {}
- X env_size = i + 10; /* arbitrary */
- X env_array = (char **) zalloc(env_size * sizeof(char *));
- X (void) memcpy((char *)env_array, (char *)environ,
- X (int) ((i + 1) * sizeof(char *)));
- X environ = env_array;
- X }
- X else if (environ != env_array)
- X message("putenv: warning: someone moved environ!\n");
- X
- X if ((e = strchr(s, '=')) != NULL)
- X ++e;
- X else
- X e = s + strlen(s);
- X
- X j = 0;
- X for (i = 0; env_array[i]; ++i)
- X {
- X if (strncmp(env_array[i], s, e - s) != 0)
- X env_array[j++] = env_array[i];
- X }
- X
- X if ((j + 1) >= env_size)
- X {
- X env_size += 10; /* arbitrary */
- X env_array = (char **) srealloc((char *)env_array,
- X env_size * sizeof(char **));
- X }
- X
- X env_array[j++] = s;
- X env_array[j] = NULL;
- X
- X environ = env_array;
- X return 0;
- X}
- X
- X#endif /* HAS_PUTENV */
- END_OF_FILE
- if test 5242 -ne `wc -c <'sysdep.c'`; then
- echo shar: \"'sysdep.c'\" unpacked with wrong size!
- fi
- # end of 'sysdep.c'
- fi
- if test -f 'uucp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'uucp.c'\"
- else
- echo shar: Extracting \"'uucp.c'\" \(3132 characters\)
- sed "s/^X//" >'uucp.c' <<'END_OF_FILE'
- X/* $Header: uucp.c,v 1.1 88/06/06 09:39:42 chip Exp $
- X *
- X * Handle mail destined for other hosts via UUCP.
- X * Deliver is intended as a very low-level program, so we don't
- X * do anything fancy here. We just hand the message to uux.
- X *
- X * $Log: uucp.c,v $
- X * Revision 1.1 88/06/06 09:39:42 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- X/*
- X * Local functions.
- X */
- X
- Xstatic int uucp_copy();
- X
- X/*----------------------------------------------------------------------
- X * Send mail to UUCP addresses (if any).
- X * This is a simple implementation: invoke uux once per address.
- X */
- X
- Xuucp_deliver()
- X{
- X struct stat st;
- X DEST *d;
- X char *uux;
- X static char uux1[] = "/bin/uux";
- X static char uux2[] = "/usr/bin/uux";
- X
- X if (stat(uux1, &st) == 0)
- X uux = uux1;
- X else if (stat(uux2, &st) == 0)
- X uux = uux2;
- X else
- X {
- X error("can't find uux!?\n");
- X return;
- X }
- X
- X for (d = first_dest(); d; d = next_dest(d))
- X {
- X FILE *uux_fp;
- X char *bang;
- X char *av[5];
- X char rmail[40];
- X char who[BUFSIZ];
- X
- X if (d->class != CL_UUCP || d->state != ST_WORKING)
- X continue;
- X
- X if (printaddrs)
- X (void) printf("%s\n", d->name);
- X
- X if (dryrun)
- X {
- X d->state = ST_DONE;
- X continue;
- X }
- X
- X bang = strchr(d->name, '!');
- X *bang = 0;
- X (void) sprintf(rmail, "%s!rmail", d->name);
- X *bang++ = '!';
- X (void) sprintf(who, "(%s)", bang);
- X
- X av[0] = "uux";
- X av[1] = "-";
- X av[2] = rmail;
- X av[3] = who;
- X av[4] = NULL;
- X if ((uux_fp = ct_popenv(eff_ct, uux, av, "w")) == NULL)
- X continue;
- X
- X if (uucp_copy(uux_fp) < 0)
- X {
- X d->state = ST_ERROR;
- X d->error = "Error piping to uux";
- X }
- X
- X if (ct_pclose(uux_fp))
- X {
- X /* Overrides any problems with uucp_copy() */
- X
- X d->state = ST_ERROR;
- X d->error = "UUCP not available to that host";
- X }
- X else
- X d->state = ST_DONE;
- X }
- X}
- X
- X/*----------------------------------------------------------------------
- X * Write the message for UUCP transmission to the given file.
- X */
- X
- Xstatic int
- Xuucp_copy(ofp)
- XFILE *ofp;
- X{
- X FILE *ifp;
- X char *p;
- X register int c;
- X int fd;
- X char buf[BUFSIZ];
- X
- X if ((fd = dup(tfd[T_HEADER])) == -1)
- X {
- X syserr("can't dup header fd");
- X return -1;
- X }
- X (void) lseek(fd, 0L, 0);
- X if ((ifp = fdopen(fd, "r")) == NULL)
- X {
- X error("can't fdopen header fd");
- X return -1;
- X }
- X
- X /*
- X * Copy the header, but tack "remote from" onto the end of the
- X * From_ line. (If it weren't for dealing with the From_ line,
- X * I'd skip stream I/O altogether and use read/write. Maybe
- X * I should save the length of the From_ line when I copy it...)
- X */
- X
- X (void) fgets(buf, GETSIZE(buf), ifp);
- X if ((p = strchr(buf, '\n')) != NULL)
- X *p = 0;
- X (void) fprintf(ofp, "%s remote from %s\n", buf, hostname);
- X
- X while ((c = getc(ifp)) != EOF)
- X (void) putc(c, ofp);
- X
- X (void) fclose(ifp);
- X
- X /*
- X * Copy the body
- X */
- X
- X if ((fd = dup(tfd[T_BODY])) == -1)
- X {
- X syserr("can't dup body fd");
- X return -1;
- X }
- X (void) lseek(fd, 0L, 0);
- X if ((ifp = fdopen(fd, "r")) == NULL)
- X {
- X error("can't fdopen body fd");
- X (void) close(fd);
- X return -1;
- X }
- X
- X while ((c = getc(ifp)) != EOF)
- X (void) putc(c, ofp);
- X
- X (void) fclose(ifp);
- X return 0;
- X}
- END_OF_FILE
- if test 3132 -ne `wc -c <'uucp.c'`; then
- echo shar: \"'uucp.c'\" unpacked with wrong size!
- fi
- # end of 'uucp.c'
- fi
- echo shar: End of shell archive.
- exit 0
-
-